package merkleTree;


import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Random;

public class Source2 {
	
	public static BigInteger digest;
	private static Tree2 root;
	private static Random r = new Random();
	
	private static boolean checkProof(BigInteger elem, ArrayList<BigInteger> proof) {
		if(proof == null) {
			System.out.println(1);
			return false;
		}
		int c1 = 0;
		if(!Tree2.hash(elem).equals(proof.get(c1))) {
			System.out.println(2);
			return false;
		}
		int c2 = 1;
		while(c2 < proof.size()-1) {
			if ((!Tree2.computeHash(proof.get(c1), proof.get(c2)).equals(proof.get(c2+1))) && 
					(!Tree2.computeHash(proof.get(c2), proof.get(c1)).equals(proof.get(c2+1)))) {
				System.out.println(Tree2.computeHash(proof.get(c1), proof.get(c2)));
				System.out.println(proof.get(c1));
				System.out.println(proof.get(c2));
				System.out.println(proof.get(c2+1));
				System.out.println(3);
				return false;
			}
			c1 += 2;
			c2 += 2;
		}
		if(!root.getHash().equals(proof.get(proof.size()-1))) {
			System.out.println(4);
			return false;
		}
		return true;
	}
	
	public static void main(String[] args) {
		long startTime = System.currentTimeMillis();
		int[] elem2 = {1,2,3,4};
		BigInteger[] elem = new BigInteger[4];
		for(int i = 0; i < 4; i++)
			elem[i] = BigInteger.valueOf(elem2[i]);
		root = Tree2.createTree(elem);
		digest = root.getHash();
		// System.out.println(digest);
		// root.printTreeInorder();
		root.printLevelOrder();
		System.out.println();
		ArrayList<BigInteger> proof2 = Tree2.proofMembership(BigInteger.valueOf(2));
		System.out.println(checkProof(BigInteger.valueOf(2), proof2));
		/*
		ArrayList<Integer> proof = Tree.proofMembership(88);
		//System.out.println(Tree.proofMembership(24));
		if(proof != null)
			for(Integer i : proof) {
				System.out.println(i +"\t");
			}
		System.out.println(proof.size());
		System.out.println(checkProof(88, proof));
		for(int i: elem) {
			ArrayList<Integer> proo = Tree.proofMembership(i);
			System.out.println(proo.size() + "\t" + i + "\t" + checkProof(i, proo));
		}
		*/
		/*BigInteger x = new BigInteger("10");
		System.out.println(x.shiftLeft(4).or(BigInteger.TEN));
		*/
		root = root.insert(root,BigInteger.valueOf(5));
		root.printLevelOrder();
		root = root.insert(root,BigInteger.valueOf(6));
		root.printLevelOrder();
		root = root.insert(root,BigInteger.valueOf(7));
		root.printLevelOrder();
		proof2 = Tree2.proofMembership(BigInteger.valueOf(5));
		System.out.println(checkProof(BigInteger.valueOf(5), proof2));
		root = root.insert(root,BigInteger.valueOf(8));
		root.printLevelOrder();
		root = root.insert(root,BigInteger.valueOf(9));
		root.printLevelOrder();
		root = root.insert(root,BigInteger.valueOf(10));
		root.printLevelOrder();
		root = root.insert(root,BigInteger.valueOf(11));
		root.printLevelOrder();
		root = root.insert(root,BigInteger.valueOf(12));
		root.printLevelOrder();
		root = root.insert(root, new BigInteger("1244556709134672538238902376194209128705432902759619814567214"));
		root.printLevelOrder();
		try {
			root = root.delete(root, new BigInteger("8"));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		root.printLevelOrder();
		proof2 = Tree2.proofMembership(BigInteger.valueOf(5));
		System.out.println(checkProof(BigInteger.valueOf(5), proof2));
		try {
			root = root.delete(root, new BigInteger("4"));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		root.printLevelOrder();
		try {
			root = root.update(root, new BigInteger("12"), new BigInteger("4"));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		root.printLevelOrder();
		proof2 = Tree2.proofMembership(BigInteger.valueOf(5));
		System.out.println(checkProof(BigInteger.valueOf(5), proof2));
		elem = new BigInteger[100000];
		for(int i = 0; i < elem.length; i++) {
			elem[i] = BigInteger.valueOf(r.nextLong());
		}
		startTime = System.currentTimeMillis();
		root = Tree2.createTree(elem);
		System.out.println("Generating a tree with " + elem.length + " elements took " + (System.currentTimeMillis()-startTime) + " ms.");
		startTime = System.currentTimeMillis();
		proof2 = Tree2.proofMembership(elem[443]);
		System.out.println("Generating the proof took " + (System.currentTimeMillis()-startTime) + " ms.");
		startTime = System.currentTimeMillis();
		System.out.println(checkProof(elem[443], proof2));
		System.out.println("Checking the proof took " + (System.currentTimeMillis()-startTime) + " ms.");
		startTime = System.currentTimeMillis();
		try {
			root.delete(root, elem[10]);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Deleting one node took " + (System.currentTimeMillis()-startTime) + " ms.");
		startTime = System.currentTimeMillis();
		try {
			root.update(root, elem[11], BigInteger.valueOf(12));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Updating one node took " + (System.currentTimeMillis()-startTime) + " ms.");
		System.out.println(checkProof(BigInteger.valueOf(12), Tree2.proofMembership(BigInteger.valueOf(12))));
	}

}
